package com.zycfc.zsf.boot.util.io;

import com.google.common.io.*;
import java.nio.charset.*;
import java.io.*;
import java.util.*;
import com.google.common.base.*;
import com.google.common.collect.*;
import org.apache.commons.lang3.*;

public abstract class FileUtils
{
    public static byte[] toByteArray(final File file) throws IOException {
        return Files.toByteArray(file);
    }
    
    public static String toString(final File file) throws IOException {
        return Files.toString(file, StandardCharsets.UTF_8);
    }
    
    public static List<String> toLines(final File file) throws IOException {
        return (List<String>)Files.readLines(file, StandardCharsets.UTF_8);
    }
    
    public static void write(final CharSequence data, final File file) throws IOException {
        Files.write(data, file, StandardCharsets.UTF_8);
    }
    
    public static void append(final CharSequence from, final File to) throws IOException {
        Files.append(from, to, StandardCharsets.UTF_8);
    }
    
    public static InputStream asInputStream(final String fileName) throws IOException {
        return new FileInputStream(getFileByPath(fileName));
    }
    
    public static OutputStream asOututStream(final String fileName) throws IOException {
        return new FileOutputStream(getFileByPath(fileName));
    }
    
    public static BufferedReader asBufferedReader(final String fileName) throws FileNotFoundException {
        return Files.newReader(getFileByPath(fileName), StandardCharsets.UTF_8);
    }
    
    public static BufferedWriter asBufferedWriter(final String fileName) throws FileNotFoundException {
        return Files.newWriter(getFileByPath(fileName), StandardCharsets.UTF_8);
    }
    
    public static void copy(final File from, final File to) throws IOException {
        Validate.notNull((Object)from);
        if (from.isDirectory()) {
            copyDir(from, to);
        }
        else {
            copyFile(from, to);
        }
    }
    
    public static void copyFile(final File from, final File to) throws IOException {
        Validate.isTrue(isFileExists(from), from + " is not exist or not a file", new Object[0]);
        Validate.notNull((Object)to);
        Validate.isTrue(!isDirExists(to), to + " is exist but it is a dir", new Object[0]);
        Files.copy(from, to);
    }
    
    public static void copyDir(final File from, final File to) throws IOException {
        Validate.isTrue(isDirExists(from), from + " is not exist or not a dir", new Object[0]);
        Validate.notNull((Object)to);
        if (to.exists()) {
            Validate.isTrue(!to.isFile(), to + " is exist but it is a file", new Object[0]);
        }
        else {
            to.mkdirs();
        }
        final File[] files = from.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; ++i) {
                final String name = files[i].getName();
                if (!".".equals(name)) {
                    if (!"..".equals(name)) {
                        copy(files[i], new File(to, name));
                    }
                }
            }
        }
    }
    
    public static void moveFile(final File from, final File to) throws IOException {
        Validate.isTrue(isFileExists(from), from + " is not exist or not a file", new Object[0]);
        Validate.notNull((Object)to);
        Validate.isTrue(!isDirExists(to), to + " is  exist but it is a dir", new Object[0]);
        Files.move(from, to);
    }
    
    public static void moveDir(final File from, final File to) throws IOException {
        Validate.isTrue(isDirExists(from), from + " is not exist or not a dir", new Object[0]);
        Validate.notNull((Object)to);
        Validate.isTrue(!isFileExists(to), to + " is exist but it is a file", new Object[0]);
        final boolean rename = from.renameTo(to);
        if (!rename) {
            if (to.getCanonicalPath().startsWith(from.getCanonicalPath() + File.separator)) {
                throw new IOException("Cannot move directory: " + from + " to a subdirectory of itself: " + to);
            }
            copyDir(from, to);
            deleteDir(from);
            if (from.exists()) {
                throw new IOException("Failed to delete original directory '" + from + "' after copy to '" + to + "'");
            }
        }
    }
    
    public static void touch(final String filePath) throws IOException {
        Files.touch(getFileByPath(filePath));
    }
    
    public static void touch(final File file) throws IOException {
        Files.touch(file);
    }
    
    public static void deleteFile(final File file) throws IOException {
        Validate.isTrue(isFileExists(file), file + " is not exist or not a file", new Object[0]);
        file.delete();
    }
    
    public static void deleteDir(final File dir) {
        Validate.isTrue(isDirExists(dir), dir + " is not exist or not a dir", new Object[0]);
        final Iterator<File> iterator = (Iterator<File>)Files.fileTreeTraverser().postOrderTraversal((Object)dir).iterator();
        while (iterator.hasNext()) {
            iterator.next().delete();
        }
    }
    
    public static List<File> listAll(final File rootDir) {
        return (List<File>)Files.fileTreeTraverser().preOrderTraversal((Object)rootDir).toList();
    }
    
    public static List<File> listFile(final File rootDir) {
        return (List<File>)Files.fileTreeTraverser().preOrderTraversal((Object)rootDir).filter(Files.isFile()).toList();
    }
    
    public static List<File> listFileWithExtension(final File rootDir, final String extension) {
        return (List<File>)Files.fileTreeTraverser().preOrderTraversal((Object)rootDir).filter((Predicate)new FileExtensionFilter(extension)).toList();
    }
    
    public static TreeTraverser<File> fileTreeTraverser() {
        return (TreeTraverser<File>)Files.fileTreeTraverser();
    }
    
    public static boolean isDirExists(final String dirPath) {
        return isDirExists(getFileByPath(dirPath));
    }
    
    public static boolean isDirExists(final File dir) {
        return dir != null && dir.exists() && dir.isDirectory();
    }
    
    public static void makeSureDirExists(final String dirPath) throws IOException {
        makeSureDirExists(getFileByPath(dirPath));
    }
    
    public static void makeSureDirExists(final File file) throws IOException {
        Validate.notNull((Object)file);
        if (file.exists()) {
            if (!file.isDirectory()) {
                throw new IOException("There is a file exists " + file);
            }
        }
        else {
            file.mkdirs();
        }
    }
    
    public static void createParentDirs(final File file) throws IOException {
        Files.createParentDirs(file);
    }
    
    public static boolean isFileExists(final String fileName) {
        return isFileExists(getFileByPath(fileName));
    }
    
    public static boolean isFileExists(final File file) {
        return file != null && file.exists() && file.isFile();
    }
    
    public static File createTempDir() {
        return Files.createTempDir();
    }
    
    public static File createTempFile() throws IOException {
        return File.createTempFile("tmp-", ".tmp");
    }
    
    public static File createTempFile(final String prefix, final String suffix) throws IOException {
        return File.createTempFile(prefix, suffix);
    }
    
    private static File getFileByPath(final String filePath) {
        return StringUtils.isBlank((CharSequence)filePath) ? null : new File(filePath);
    }
    
    public static File toFile(final String originalFilename, final InputStream inputStream) throws IOException {
        final File file = new File(originalFilename);
        inputStreamToFile(inputStream, file);
        return file;
    }
    
    public static void inputStreamToFile(final InputStream ins, final File file) {
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            int len = 0;
            final byte[] buffer = new byte[8192];
            while ((len = ins.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            os.close();
            ins.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            try {
                os.close();
                ins.close();
            }
            catch (IOException ex) {}
        }
    }
    
    public static final class FileExtensionFilter implements Predicate<File>
    {
        private final String extension;
        
        private FileExtensionFilter(final String extension) {
            this.extension = extension;
        }
        
        public boolean apply(final File input) {
            return input.isFile() && this.extension.equals(FilePathUtils.getFileExtension(input));
        }
    }
}
